﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common.Logging;

namespace MediaScraper.Common
{
    public static class LogWriter
    {
        /// <summary>
        /// Logs an simple error string.
        /// </summary>
        /// <remarks>Should used to indicate logical or business errors wich does not raise exceptions.</remarks>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        public static void LogError(LoggingCategories category, string message)
        {
            LogError(category, message, null);
        }

        /// <summary>
        /// Logs an error message as a result of an exception
        /// </summary>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        /// <param name="ex">The exception write to the log</param>
        public static void LogError(LoggingCategories category, string message, Exception ex)
        {
            WriteLog(category, message, TraceEventType.Error, LogPriority.Error, ex);
        }

        /// <summary>
        /// Logs an warning message as a result of an exception
        /// </summary>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        /// <param name="ex"> </param>
        public static void LogFatal(LoggingCategories category, string message, Exception ex)
        {
            WriteLog(category, message, TraceEventType.Critical, LogPriority.Warning, ex);
        }

        /// <summary>
        /// Logs an warning message as a result of an exception
        /// </summary>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        public static void LogWarning(LoggingCategories category, string message)
        {
            WriteLog(category, message, TraceEventType.Warning, LogPriority.Warning);
        }

        /// <summary>
        /// Logs an info message as a result of an exception
        /// </summary>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        public static void LogInfo(LoggingCategories category, string message)
        {
            WriteLog(category, message, TraceEventType.Information, LogPriority.Info);
        }

        /// <summary>
        /// Logs an debug message as a result of an exception
        /// </summary>
        /// <param name="category"> </param>
        /// <param name="message">The message to log</param>
        public static void LogDebug(LoggingCategories category, string message)
        {
            WriteLog(category, message, TraceEventType.Verbose, LogPriority.Debug);
        }

        private static void WriteLog(LoggingCategories domain, string message, TraceEventType severity, LogPriority prio, Exception ex = null)
        {
            try
            {
                var logger = GetLogger();
                var category = Enum.GetName(typeof(LoggingCategories), domain);

                var msg = new StringBuilder();
                msg.AppendFormat("[{0}] ", category);
                msg.Append(message);

                switch (severity)
                {
                    case TraceEventType.Verbose:
                        logger.Trace(msg.ToString(), ex);
                        break;
                    case TraceEventType.Information:
                        logger.Info(msg.ToString(), ex);
                        break;
                    case TraceEventType.Warning:
                        logger.Warn(msg.ToString(), ex);
                        break;
                    case TraceEventType.Critical:
                        logger.Fatal(msg.ToString(), ex);
                        break;
                    case TraceEventType.Error:
                        logger.Error(msg.ToString(), ex);
                        break;
                    default:
                        logger.Error(msg.ToString(), ex);
                        break;
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(string.Format("Error logging message: {0}. Message was: {1}", e, message));
            }
        }

        private static ILog _logger;
        private static ILog GetLogger()
        {
            return _logger ??
                   (_logger = LogManager.GetCurrentClassLogger());
        }
    }

    public enum LogPriority
    {
        /// <summary>
        /// Indicates an error.
        /// </summary>
        Error = 0,
        /// <summary>
        /// Indicates a warning.
        /// </summary>
        Warning = 1,
        /// <summary>
        /// Indicates an audit message to create an audit trail of milestones
        /// within the application.
        /// </summary>
        Audit = 2,
        /// <summary>
        /// Indicates a simple info.
        /// </summary>
        Info = 3,
        /// <summary>
        /// Indicates a debug info.
        /// </summary>
        Debug = 4
    }

    public enum LoggingCategories
    {
        Scraper,
        Infrastructure,
        Localization,
        Application,
        UI,
        DataAccess,
        Adapters,
        Agents
    }
}
